﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace ICSharpCode.WinFormsUI.Controls
{
    public partial class NRichTextViewer : Control
    {
        private int _padding = 6;        
        private int _lineIndex = 0;
        private int _lineHeight = 17;
        private int _lastLineIndex = 0;
        private int _topPos = 0;
        private int _textColumnWidth = 0;
        private int _hScollerPos = 0;
        private int _vScollerPos = 0;
        private int _numberColumnWidth = 24;       
 
        private Font _textFont = new Font("宋体", 9.0F);

        public int SelectedIndex { get; set; }

        public AutoScaleMode AutoScaleMode = AutoScaleMode.None;

        public Font TextFont
        {
            get { return _textFont; }
            set { _textFont = value; }
        }

        private List<LineItem> _list;
        public List<LineItem> List
        {
            get
            {
                return _list;
            }
            set
            {
                _list = value;                
                this.Invalidate();

            }
        }

        private StringFormat _lineStringFormat;

        private TextFormatFlags _textFormatFlags = TextFormatFlags.Default;

        private HScrollBar _hScrollBar = new HScrollBar();
        private VScrollBar _vScrollBar = new VScrollBar();

        private ScrollBars _scrollBars;
        public ScrollBars ScrollBars
        {
            get { return _scrollBars; }
            set
            {
                _scrollBars = value;
                switch (_scrollBars)
                {                   
                    case System.Windows.Forms.ScrollBars.None:
                        _textFormatFlags = TextFormatFlags.EndEllipsis;
                        break;
                    case System.Windows.Forms.ScrollBars.Horizontal:
                        _textFormatFlags = TextFormatFlags.Default;
                        _hScrollBar.Dock = DockStyle.Bottom;
                        this.Controls.Add(_hScrollBar);
                        break;
                    case System.Windows.Forms.ScrollBars.Vertical:
                        _textFormatFlags = TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl;
                        _vScrollBar.Dock = DockStyle.Right;
                        this.Controls.Add(_vScrollBar);
                        break;
                }
                _vScrollBar.SmallChange = _lineHeight;
                this.Invalidate();
            }
        }

        public NRichTextViewer()
        {
            InitializeComponent();           
            InitializeControls();
            InitializeEventHandlers();          
        }

        protected void InitializeEventHandlers()
        {
            _vScrollBar.Scroll += VScrollBar_Scroll;
        }

        protected void InitializeControls()
        {
            this.DoubleBuffered = true;
            this.BackColor = Color.White;
            this.ScrollBars = ScrollBars.None;
            this.TextFont = new Font("宋体", 9.0F);           
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            //this.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawControlRender(e.Graphics);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            this.ResetScrollBar();
            this.Invalidate();
        }

        private void ResetScrollBar()
        {
            _hScollerPos = 0;
            _vScollerPos = 0;
            _vScrollBar.Value = 0;
        }

        private void MeasureScrollBar()
        {
            this._vScrollBar.Minimum = 0;
            if ((_lastLineIndex + 2) * _lineHeight > this.Height)
            {
                this._vScrollBar.Maximum = (_lastLineIndex + 2) * _lineHeight - this.Height;
                this._vScrollBar.Visible = true;
            }
            else
            {
                this._vScrollBar.Maximum = 0;
                this._vScrollBar.Visible = false;
            }
        }

        protected void DrawControlRender(Graphics graphic)
        {
            if (this.List != null)
            {
                _topPos = 0;               
                _lineIndex = 0;
                _lastLineIndex = 0;

                if (_numberColumnWidth > 0)
                {
                    graphic.FillRectangle(new SolidBrush(SystemColors.AppWorkspace), new Rectangle(0, 0, _numberColumnWidth, this.Height));
                }

                foreach (LineItem item in this.List)
                {
                    int tempLineCount = 1;
                    string tempLineText = item.LineText;
                    if (string.IsNullOrEmpty(item.LineText))
                    {
                        tempLineText = "测试文本";
                    }
                    Size textMeasureSize = TextRenderer.MeasureText(graphic, tempLineText, TextFont, new Size(this.Width, _lineHeight));
                    _lineHeight = (int)textMeasureSize.Height;

                    switch (_textFormatFlags)
                    {
                        case TextFormatFlags.Default:
                        case TextFormatFlags.EndEllipsis:
                            break;
                        default:
                            tempLineCount = textMeasureSize.Width % (this.Width - 2 * _padding - _numberColumnWidth) == 0 ?
                      textMeasureSize.Width / (this.Width - 2 * _padding - _numberColumnWidth) : textMeasureSize.Width / (this.Width - 2 * _padding - _numberColumnWidth) + 1;
                            break;
                    }

                    item.Bound = new Rectangle(_numberColumnWidth, _topPos + _padding + _vScollerPos, (this.Width - 1 * _padding - _numberColumnWidth), (int)(tempLineCount * _lineHeight));

                    LineRenderer.FillBackgound(graphic, item.LineBackColor, item.Bound);
                    TextRenderer.DrawText(graphic, item.LineText, TextFont, item.Bound, item.LineForeColor, Color.Transparent, _textFormatFlags);

                    if (_numberColumnWidth > 0)
                    {
                        var numberSize = TextRenderer.MeasureText((_lineIndex + 1).ToString(), this.TextFont);
                        if (_numberColumnWidth <= 28 && numberSize.Width > _numberColumnWidth)
                        {
                            _numberColumnWidth = numberSize.Width;
                            this.Invalidate();
                        }
                        TextRenderer.DrawText(graphic, (_lineIndex + 1).ToString(), this.TextFont, new Rectangle(0, _topPos + _padding + _vScollerPos, _numberColumnWidth, (int)(tempLineCount * _lineHeight)), Color.Black, Color.Transparent, TextFormatFlags.WordEllipsis | TextFormatFlags.Right | TextFormatFlags.VerticalCenter);
                    }

                    _topPos += (int)(tempLineCount * _lineHeight);
                    _lineIndex += 1;
                    _lastLineIndex += tempLineCount;

                }                

                MeasureScrollBar();
            }

            ControlPaint.DrawBorder(graphic, this.ClientRectangle, Color.FromArgb(255, 139, 139, 139), ButtonBorderStyle.Solid);

        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            if (!this._vScrollBar.Visible)
                return;
            int num1 = -e.Delta / _lineHeight;
            if (this._vScrollBar.Value + num1 < this._vScrollBar.Minimum || this._vScrollBar.Value + num1 > this._vScrollBar.Maximum)
                return;
            int oldValue = this._vScrollBar.Value;
            int num2 = oldValue + num1;
            VScrollBar vscrollBar = this._vScrollBar;
            int num3 = vscrollBar.Value + num1;
            vscrollBar.Value = num3;
            this.VScrollBar_Scroll((object)this, new ScrollEventArgs(ScrollEventType.SmallDecrement, oldValue, this._vScrollBar.Value));
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (this.List == null) return;

            for (int index = 0; index < List.Count; index++)
            {               
                if (this.List[index].Bound.Contains(e.Location))
                {                   
                    this.List[index].LineForeColor = Color.White;
                    this.List[index].LineBackColor = SystemColors.MenuHighlight;
                    this.SelectedIndex = index;                    
                }
                else
                {
                    this.List[index].LineForeColor = Color.Black;
                    this.List[index].LineBackColor = Color.Transparent;
                }
            }

            this.Invalidate();

        }         

        private void VScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            _vScollerPos += -(e.NewValue - e.OldValue);
            this.Invalidate();
        }

        public class LineItem
        {
            public int LineNumber { get; set; }
            public string LineText { get; set; }
            public Color LineForeColor { get; set; }
            public Color LineBackColor { get; set; }
            public TextAlign LineTextAlign { get; set; }
            public Rectangle Bound { internal set; get; }
            public LineItem(string Text, Color ForeColor, Color BackColor, TextAlign TextAlign)
            {
                this.LineText = Text;
                this.LineForeColor = ForeColor;
                this.LineBackColor = BackColor;
                this.LineTextAlign = TextAlign;
            }
            public LineItem(string Text)
                : this(Text, Color.Black, Color.White, TextAlign.Left)
            {

            }
        }

        public class LineRenderer
        {
            public static void FillBackgound(Graphics graphic, Color backgroundColor, Rectangle bound)
            {
                graphic.FillRectangle(new SolidBrush(backgroundColor), bound);
            }
        }

        public enum TextAlign
        {
            Left,
            Center,
            Right
        }

    }
    

}
